package tableaux;

import java.util.HashSet;
import java.util.Set;

import option.KBVocabulary;

import kb.RBox;
import kb.TBox;

import entities.Individual;
import entities.assertion.ConceptAssertion;
import entities.concept.AndConcept;
import entities.concept.Concept;
import entities.concept.DomainConcept;
//import entities.concept.ExistsConcept;
import entities.concept.Nominal;
import entities.concept.NotConcept;
import entities.concept.OrConcept;
import entities.concept.PConcept;
import entities.concept.UniversalConcept;
import entities.concept.QuantifiedConcept;
import entities.role.Role;

/**
 * This class provides methods to generate guards for the original queries.
 * 
 * @author j55wu
 * 
 */
public class DerivativeConcept {

	// For a given a:C, return (a AND DEFs AND ~C)
	public static Concept generateFromAssertion(ConceptAssertion ca,
			Individual itp, TBox tb) {
		Set<Concept> ret = new HashSet<Concept>();
		Nominal o = Nominal.getNominal(ca.getIndividual().getName(), true);
		o.intepretNominal(itp);
		Concept nc = preprocessor.Simplification.NNF(ca.getConcept(), false);
		ret.add(nc);
		ret.add(o);
		PConcept defa = PConcept.newGuardPConcept(o);
		ret.add(defa);
		Concept dc = getRoleGuards(ca.getConcept(), tb);
		if (dc != null) {
			ret.add(dc);
		}
		return new AndConcept(ret);
	}

	private static Concept getRoleGuards(Concept rc, TBox tb) {
		if (rc instanceof DomainConcept) {
			return getFeatureGuards(rc);
		} else if (rc instanceof NotConcept) {
			NotConcept nc = (NotConcept) rc;
			return getRoleGuards(nc.getConcept(), tb);
		} else if (rc instanceof AndConcept) {
			Set<Concept> ret = new HashSet<Concept>();
			for (Concept c : ((AndConcept) rc).getConceptSet()) {
				Concept gc = getRoleGuards(c, tb);
				if (gc != null)
					ret.add(gc);
			}
			if (ret.size() == 1) {
				return ret.iterator().next();
			} else if (ret.size() > 1) {
				return new AndConcept(ret);
			}
		} else if (rc instanceof OrConcept) {
			Set<Concept> ret = new HashSet<Concept>();
			for (Concept c : ((OrConcept) rc).getConceptSet()) {
				Concept gc = getRoleGuards(c, tb);
				if (gc != null)
					ret.add(gc);
			}
			if (ret.size() == 1) {
				return ret.iterator().next();
			} else if (ret.size() > 1) {
				return new AndConcept(ret);
			}
		} else if(rc instanceof QuantifiedConcept){
			//either forall or exists R.C
			QuantifiedConcept qc = (QuantifiedConcept) rc;
			Role r = qc.getRole();
			Concept defr = PConcept.newGuardPConcept(r);
//			if(tb.getRoleBox().isComplexRole(r)){
//				defr = new AndConcept(defr, PConcept.newGuardPConcept(RBox.getInverseRole(r)));
//			}
			//get all subrole defs (for H)
//			if(tb.getRoleBox().getSubRolesMap().containsKey(r)){
//				for(Role sub:tb.getRoleBox().getAllSubRoles(r)){
//					defr = new AndConcept(defr, PConcept.newGuardPConcept(sub));
//				}
//			}
			Concept rrc = getRoleGuards(qc.getFiller(), tb);
//			Concept filler = KBVocabulary.CONCEPT_TOP;
			Concept filler = KBVocabulary.QUERY_GUARD;
			if (rrc != null) {
				filler = new AndConcept(filler, rrc);
			}
			return new AndConcept(defr, new UniversalConcept(r, filler));
		}
//		} else if (rc instanceof ExistsConcept) {
//			ExistsConcept ec = (ExistsConcept) rc;
//			Role r = ec.getRole();
//			Concept defr = PConcept.newGuardPConcept(r);
//			Concept defir = PConcept.newGuardPConcept(Role.getInverseRole(r));
//			Concept rrc = getRoleGuards(ec.getFiller());
//			// Concept filler = defir;
//			Concept filler = KBVocabulary.CONCEPT_TOP;
//			if (rrc != null) {
//				filler = new AndConcept(filler, rrc);
//			}
//			return new AndConcept(defr, new UniversalConcept(r, filler));
//			// return new AndConcept(defr, new ExistsConcept(r, filler));
//		} else if (rc instanceof UniversalConcept) {
//			UniversalConcept uc = (UniversalConcept) rc;
//			Role r = uc.getRole();
//			Concept defr = PConcept.newGuardPConcept(r);
//			Concept defir = PConcept.newGuardPConcept(Role.getInverseRole(r));
//			Concept rrc = getRoleGuards(uc.getFiller());
//			// Concept filler = defir;
//			Concept filler = KBVocabulary.CONCEPT_TOP;
//			if (rrc != null) {
//				filler = new AndConcept(filler, rrc);
//			}
//			return new AndConcept(defr, new UniversalConcept(r, filler));
//		}
		return null;
	}

	private static Concept getFeatureGuards(Concept fc) {
		if (fc instanceof DomainConcept) {
			Set<Concept> ret = new HashSet<Concept>();
			for (Role f : fc.extractFeatures()) {
				ret.add(PConcept.newGuardPConcept(f));
			}
			if (ret.size() == 1) {
				return ret.iterator().next();
			} else if (ret.size() > 1) {
				return new AndConcept(ret);
			}
		} else if (fc instanceof NotConcept) {
			NotConcept nc = (NotConcept) fc;
			return getFeatureGuards(nc.getConcept());
		} else if (fc instanceof AndConcept) {
			Set<Concept> ret = new HashSet<Concept>();
			for (Concept c : ((AndConcept) fc).getConceptSet()) {
				Concept gc = getFeatureGuards(c);
				if (gc != null)
					ret.add(gc);
			}
			if (ret.size() == 1) {
				return ret.iterator().next();
			} else if (ret.size() > 1) {
				return new AndConcept(ret);
			}
		} else if (fc instanceof OrConcept) {
			Set<Concept> ret = new HashSet<Concept>();
			for (Concept c : ((OrConcept) fc).getConceptSet()) {
				Concept gc = getFeatureGuards(c);
				if (gc != null)
					ret.add(gc);
			}
			if (ret.size() == 1) {
				return ret.iterator().next();
			} else if (ret.size() > 1) {
				return new AndConcept(ret);
			}
		}
		return null;
	}

}
